<?php

namespace app\ws\controller;

use app\admin\model\AdminUser;
use app\admin\model\Company;
use app\company\model\CompanyOrderStorage;
use app\company\model\DeliverCar;
use app\company\model\Store;
use app\company\model\StoreOrder;
use app\company\model\StoreScreen;
use app\company\model\WarehouseStorageGoodsLogs;
use Firebase\JWT\JWT;
use Firebase\JWT\Key;
use Random\RandomException;
use Swoole\Http\Request;
use Swoole\WebSocket\Frame;
use Swoole\WebSocket\Server;
use think\App;
use think\db\exception\DataNotFoundException;
use think\db\exception\DbException;
use think\db\exception\ModelNotFoundException;
use think\facade\Config;

/**
 * 大屏演示版本
 */
class WhTrack

{

    //不要使用静态变量
    public array $tickId = [];//定时器ID

    private array $config = [
        'warehouse' => [
            'total_out_money' => 3267916.38,
            'total_out'       => 130906,
            'total_in_money'  => 6292553.60,
            'total_in'        => 410050,
            'today_in'        => 82,
            'today_out'       => 257,
            'total_sales'     => 3255916.38,
            'total_store'     => 4501,
            'total_car'       => 15
        ],

        'overview' => [
            [
                "amount"     => 289907.00,
                "goods_name" => "饮料"
            ],
            [
                "amount"     => 344603.00,
                "goods_name" => "面点"
            ],
            [
                "amount"     => 436545.20,
                "goods_name" => "标品"
            ],
            [
                "amount"     => 398943.04,
                "goods_name" => "日用百货"
            ],
            [
                "amount"     => 573235.00,
                "goods_name" => "设备"
            ],
            [
                "amount"     => 423453.82,
                "goods_name" => "耗材"
            ],
            [
                "amount"     => 344895.41,
                "goods_name" => "酒类"
            ],
            [
                "amount"     => 350026.66,
                "goods_name" => "其他"
            ]
        ]
    ];

    /**
     * 处理连接建立事件
     * @param Server $server
     * @param Request $request
     * @return void
     * @throws DataNotFoundException
     * @throws DbException
     * @throws ModelNotFoundException
     * @throws \JsonException
     */
    public function onOpen(Server $server, Request $request): void
    {
        //检查数据库连接
        checkDb();
    }

    /**
     * 处理消息事件
     * @param Server $server
     * @param Frame $frame
     * @return void
     */
    public function onMessage(Server $server, Frame $frame): void
    {
        $arr = json_decode($frame->data, 1);
        //校验参数
        if (!$this->check($server, $frame->fd, ['type'], $arr)) return;
        //心跳包
        if ($arr['type'] == 'ping') {
            $this->ping($server, $frame);
            return;
        }
        if ($arr['type'] == 'default') {
            // 合伙人地图位置
            $this->mapLocation($server, $frame, $arr);
            // 出入库数据
            $this->warehouseData($server, $frame, $arr);
            // 仓内概况
            $this->warehouseOverview($server, $frame, $arr);
            // 销售数据
            $this->salesList($server, $frame, $arr);
            // 经营数据
            $this->operateData($server, $frame, $arr);
            // 仓库商品预警
            $this->whGoodsWarring($server, $frame, $arr);
            // 门店订单
            $this->storeOrder($server, $frame, $arr);
        }
        if ($arr['type'] == 'sales_list') {
            // 销售数据
            $this->salesList($server, $frame, $arr);
        }

        if ($arr['type'] == 'store_order') {
            // 门店订单
            $this->storeOrder($server, $frame, $arr);
        }
    }

    /**
     * 心跳包
     * @param $server
     * @param $frame
     * @return void
     */
    public function ping($server, $frame): void
    {
        $server->push($frame->fd, json_encode(['type' => "pong"]));
    }

    /**
     * 合伙人地图位置
     * @param Server $server
     * @param Frame $frame
     * @param mixed $arr
     * @return void
     * @throws DataNotFoundException
     * @throws DbException
     * @throws ModelNotFoundException
     * @throws \JsonException
     */
    public function mapLocation(Server $server, Frame $frame, mixed $arr): void
    {
        $company = [
            'name'     => '邓州市锦玉良源商贸有限公司',
            'location' => '河南省南阳市邓州市'
        ];

        $store = StoreScreen::where('company_id', 14)
                            ->where('status', 1)
                            ->field('name,long,lat')
                            ->select();

        $wh = [
            'name' => '京东2号仓',
            'long' => '112.112258',
            'lat'  => '32.640788'
        ];
        $server->push($frame->fd,
                      json_encode(['code' => 200, 'type' => 'map', 'data' => compact('company', 'store', 'wh')],
                                  JSON_THROW_ON_ERROR));
    }

    /**
     * 出入库数据
     * @param Server $server
     * @param Frame $frame
     * @param mixed $arr
     * @return void
     * @throws \JsonException
     */
    public function warehouseData(Server $server, Frame $frame, mixed $arr): void
    {
        $warehouse_data = $this->config['warehouse'];
        $server->push($frame->fd, json_encode(['code' => 200, 'type' => 'warehouse', 'data' => $warehouse_data],
                                              JSON_THROW_ON_ERROR));

        $this->tickId[$frame->fd] = $server->tick(40000, function () use ($server, $frame, $arr) {
            $this->config['warehouse']['today_in']        += 1;
            $this->config['warehouse']['today_out']       += 2;
            $this->config['warehouse']['total_out_money'] += 11050;
            $this->config['warehouse']['total_in_money']  += 11050;
            $this->config['warehouse']['total_out']       += 1050;
            $this->config['warehouse']['total_in']        += 11050;
            $this->config['warehouse']['total_sales']     += 1050;
            $server->push($frame->fd,
                          json_encode(['code' => 200, 'type' => 'warehouse', 'data' => $this->config['warehouse']],
                                      JSON_THROW_ON_ERROR));
        });
    }

    /**
     * 仓内概览
     * @param Server $server
     * @param Frame $frame
     * @param mixed $arr
     * @return void
     * @throws \JsonException
     */
    public function warehouseOverview(Server $server, Frame $frame, mixed $arr): void
    {
        $warehouse_overview = $this->config['overview'];
        $total_amount       = array_sum(array_column($this->config['overview'], 'amount'));
        $server->push($frame->fd, json_encode(['code' => 200, 'type' => 'warehouse_overview',
                                               'data' => compact('warehouse_overview', 'total_amount')],
                                              JSON_THROW_ON_ERROR));

        $this->tickId[$frame->fd] = $server->tick(40000, function () use ($server, $frame, $arr) {
            foreach ($this->config['overview'] as &$item) {
                $item['amount'] += 1000;
            }
            $warehouse_overview = $this->config['overview'];
            $total_amount       = array_sum(array_column($this->config['overview'], 'amount'));
            $server->push($frame->fd, json_encode(['code' => 200, 'type' => 'warehouse_overview',
                                                   'data' => compact('warehouse_overview', 'total_amount')],
                                                  JSON_THROW_ON_ERROR));
        });
    }

    /**
     * 销售列表
     * @throws RandomException
     */
    public function salesList(Server $server, Frame $frame, mixed $arr): void
    {
        $def_num = 7;
        $list    = [];

        $time = date('Y-m-d');
        $num  = $def_num;

        for ($i = 0; $i < $num + 1; $i++) {
            $date          = date('Y-m-d', strtotime('-' . $i . ' day', strtotime($time)));
            $arr['date']   = $date;
            $arr['amount'] = number_format(random_int(60000, 150000), 2);
            $list[]        = $arr;
        }
        $server->push($frame->fd,
                      json_encode(['code' => 200, 'type' => 'sales_list', 'data' => $list], JSON_THROW_ON_ERROR));
    }

    /**
     * 经营数据
     * @param Server $server
     * @param Frame $frame
     * @param mixed $arr
     * @return void
     * @throws DataNotFoundException
     * @throws DbException
     * @throws ModelNotFoundException
     * @throws \JsonException
     */
    public function operateData(Server $server, Frame $frame, mixed $arr): void
    {
        $list = [
            'purchase_count'    => 908,
            'wh_count'          => 10,
            'wh_area_count'     => 30,
            'wh_position_count' => 1000,
            'car_count'         => 15,
            'goods_count'       => 320800,
            'sales_amount'      => 130096
        ];
        $server->push($frame->fd,
                      json_encode(['code' => 200, 'type' => 'operate_data', 'data' => $list], JSON_THROW_ON_ERROR));
    }

    public function whGoodsWarring(Server $server, Frame $frame, mixed $arr)
    {
        $def_num = 7;
        $list    = [];
        $time    = strtotime(date('Y-m-d')); // 获取当前时间的时间戳
        // 当前预警数量
        $now_expired      = 0;
        $now_near_expired = 4;
        for ($i = 0; $i <= $def_num; $i++) {
            $date        = date('Y-m-d', strtotime('-' . $i . ' day', $time));
            $arr['date'] = $date;
            $arr['num']  = random_int(0, 8);
            $list[]      = $arr;
        }
        $server->push($frame->fd, json_encode(['code' => 200, 'type' => 'wh_goods_warring',
                                               'data' => compact('now_expired', 'now_near_expired', 'list')],
                                              JSON_THROW_ON_ERROR));
    }

    /**
     * 订单列表数据
     * @param Server $server
     * @param Frame $frame
     * @param mixed $arr
     * @return void
     * @throws \JsonException
     */
    public function storeOrder(Server $server, Frame $frame, mixed $arr): void
    {
        $list = StoreScreen::where('company_id', 14)
                           ->where('status', 1)
                           ->field('name as store_name')
                           ->select()
                           ->each(function ($item) {
                               $item->no          = "XS" . date('YmdHis') . mt_rand(100000, 999999);
                               $item->create_time = date('Y-m-d H:i:s', time() - mt_rand(100000, 999999));

                           });
        $server->push($frame->fd,
                      json_encode(['code' => 200, 'type' => 'store_order', 'data' => $list], JSON_THROW_ON_ERROR));

    }

    /**
     * 处理连接关闭事件
     * @param Server $server
     * @param int $fd
     * @param int $reactorId
     * @return void
     */
    public function onClose(Server $server, int $fd, int $reactorId): void
    {
        //删除定时器
        //注:虽然能自动销毁,但是执行的顺序有问题,先执行了关闭,然后定时器还会推送一条信息,导致一个notices错误和一个error错误,这个时候才会被回收,所以关闭之前要清理定时器
        $this->delTickId($server, $fd);
    }

    /**
     * 清除定时器
     * @param $server
     * @param $fd
     * @return void
     */
    public function delTickId($server, $fd): void
    {
        if (isset($this->tickId[$fd])) {
            $server->clearTimer($this->tickId[$fd]); // 清除定时器
        }
    }


    /**
     * 验证参数  disconnect 方法不会立即终止 需要配合return
     * @param $server
     * @param $fd
     * @param $field
     * @param $arr
     * @return bool
     */
    public function check($server, $fd, $field, $arr): bool
    {
        if (!$arr) {
            echo "数据格式不正确1";
            $server->disconnect($fd, SWOOLE_WEBSOCKET_CLOSE_PROTOCOL_ERROR, "数据格式不正确");
            return false;
        }
        //检验数据
        foreach ($field as $v) {
            if (!isset($arr[$v]) || !$arr[$v]) {
                echo "数据格式不正确2";
                $server->disconnect($fd, SWOOLE_WEBSOCKET_CLOSE_PROTOCOL_ERROR, "数据格式不正确");
                return false;
            }
        }
        return true;
    }

}